package com.cd.university.service.impl;

import com.cd.university.common.RestResult;
import com.cd.university.common.UniversityConstants;
import com.cd.university.common.utils.PageUtil;
import com.cd.university.db.mapper.ProjectExamineMapper;
import com.cd.university.db.mapper.ProjectMapper;
import com.cd.university.db.pojo.Message;
import com.cd.university.db.pojo.Project;
import com.cd.university.db.pojo.ProjectExamine;
import com.cd.university.service.MessageService;
import com.cd.university.service.ProjectExamineService;
import com.cd.university.vo.ProjectExamineVo;
import com.cd.university.vo.ProjectVo;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 陈栋
 * @create 2021/11/1 19:07
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ProjectExamineServiceImpl implements ProjectExamineService {

    @Autowired
    private ProjectExamineMapper projectExamineMapper;

    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private ProjectServiceImpl projectService;

    @Autowired
    private MessageService messageService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 项目初审审核表的所有内容，key为审核id，value为ProjectExamineVo
     */
    private HashMap<Integer, ProjectExamineVo> peFirstMaps = new HashMap<>();

    /**
     * 项目复审审核表的所有内容,key为审核id，value为ProjectExamineVo
     */
    private HashMap<Integer, ProjectExamineVo> peSecondMaps = new HashMap<>();


    @Override
    public RestResult findAllProject(Integer pageNum,Integer pageSize,Integer flag) {
        ArrayList<ProjectExamineVo> result = new ArrayList<>();

        // 判断是初审还是二审
        HashMap<Integer, ProjectExamineVo> map = flag==1?peFirstMaps:peSecondMaps;
        for (Map.Entry<Integer, ProjectExamineVo> entry : map.entrySet()) {
            ProjectExamineVo examineVo = entry.getValue();

            result.add(examineVo);
        }

        PageInfo pageInfo = PageUtil.startPage(pageNum, pageSize, result);
        return RestResult.success("审核的全部数据为：")
                .put("data",pageInfo);
    }

    @Override
    public RestResult searchPEByName(Integer pageNum, Integer pageSize, String name,Integer flag) {
        ArrayList<ProjectExamineVo> result = new ArrayList<>();

        // 判断是初审还是二审
        HashMap<Integer, ProjectExamineVo> map = flag==1?peFirstMaps:peSecondMaps;
        for (Map.Entry<Integer, ProjectExamineVo> entry : map.entrySet()) {
            ProjectExamineVo examineVo = entry.getValue();
            if (examineVo.getProjectName().contains(name)) {
                result.add(examineVo);
            }
        }

        PageInfo pageInfo = PageUtil.startPage(pageNum, pageSize, result);
        return RestResult.success("查询的所有数据全部数据为：")
                .put("data",pageInfo);
    }

    @Override
    public RestResult searchPEByDepartmentId(Integer pageNum, Integer pageSize, Integer departmentId, Integer flag) {
        ArrayList<ProjectExamineVo> result = new ArrayList<>();

        // 判断是初审还是二审
        HashMap<Integer, ProjectExamineVo> map = flag==1?peFirstMaps:peSecondMaps;
        for (Map.Entry<Integer, ProjectExamineVo> entry : map.entrySet()) {
            ProjectExamineVo examineVo = entry.getValue();
            if (examineVo.getDepartmentId().equals(departmentId)) {
                result.add(examineVo);
            }
        }
        PageInfo pageInfo = PageUtil.startPage(pageNum, pageSize, result);
        return RestResult.success("查询的所有数据全部数据为：")
                .put("data",pageInfo);
    }

    @Override
    public RestResult approvedExamine(Integer peId, Integer reviewerId,Integer flag) {

        if (flag.equals(1)) {
            approvedProject(peId,reviewerId,"初审通过",UniversityConstants.PROJECT_STATUS_FIRST_PASS);
        }else if (flag.equals(2)) {
            approvedProject(peId,reviewerId,"复审通过",UniversityConstants.PROJECT_STATUS_SECOND_PASS);
        }else {
            return RestResult.failure("标记为错误，请检查");
        }

        // 向消息表中插入数据
        ProjectExamineVo examineVo = peFirstMaps.get(peId);
        String projectName = examineVo.getProjectName();
        Project project = projectMapper.searchProjectByProjectName(projectName);
        Integer messageStatusId = flag==1?UniversityConstants.MESSAGE_STATUS_FIRST_PASS:UniversityConstants.MESSAGE_STATUS_SECOND_PASS;

        messageService.projectApproved(new Message(project.getProjectId(),
                projectName,reviewerId,null,null,messageStatusId));

        return RestResult.success("审核成功");
    }

    /**
     * 用户项目的审核通过
     * @param peId 审核id
     * @param reviewerId 审核人id
     * @param examineStatus 审核的项目状态
     * @param statusId 状态id
     */
    private void approvedProject(Integer peId, Integer reviewerId, String examineStatus, Integer statusId) {
        HashMap<Object, Object> param = new HashMap<>();
        param.put("peId",peId);
        param.put("reviewerId",reviewerId);
        // 设置项目的初审通过
        param.put("statusId", statusId);
        param.put("examineStatus",examineStatus);
        // 设置通过时间
        Date date = new Date(System.currentTimeMillis());
        param.put("applyTime",date);

        // 根据审核id拿到项目审核Impl中的Java缓存中的ProjectExamineVo
        ProjectExamineVo projectExamineVo = peFirstMaps.get(peId);

        String projectName = projectExamineVo.getProjectName();
        param.put("projectName",projectName);

        // 根据项目的名称向项目表中修改项目的状态
        projectMapper.changeProjectStatus(param);
        // 根据项目的名称向项目审核表中修改项目的状态
        projectExamineMapper.changePEStatus(param);

        // 更新项目审核中的内容
        projectExamineVo.setStatusId(statusId);
        projectExamineVo.setExamineStatus(examineStatus);
        projectExamineVo.setApplyTime(date);
        projectExamineVo.setReviewerId(reviewerId);
        projectExamineVo.setPeId(peId);
        peFirstMaps.put(peId,projectExamineVo);

        // 更新复审中的缓存
        peSecondMaps.put(peId,projectExamineVo);

        // 更新Redis中的Project信息
        projectService.updateStatusFromRedis(statusId,
                null,null,
                projectName);
    }

    /**
     * 通过项目的id查询项目审核的Vo对象
     * @param projectId 项目id
     * @return ProjectExamineVo对象
     */
    public ProjectExamineVo searchExamineVoById(Integer projectId) {
        if (projectId==null) {
            return null;
        }
        // 通过projectService拿到项目Vo
        ProjectVo projectVo = projectService.getProjectVoByProjectId(projectId);

        // 拿到项目名称
        String projectName = projectVo.getProjectName();
        // 遍历查找名字与项目名相同的
        for (Map.Entry<Integer, ProjectExamineVo> entry : peFirstMaps.entrySet()) {
            if (entry.getValue().getProjectName().equals(projectName)) {
                return entry.getValue();
            }
        }

        return null;
    }

    /**
     * 每隔一个小时更新一次项目审核表
     */
    @Override
    @Async
    @Scheduled(initialDelay = 5000,fixedRate = 1000 * 60 * 60)
    public void updateProjectExamine() {
        ValueOperations opsForValue = redisTemplate.opsForValue();
        List<ProjectVo> projectVoList = new ArrayList<>();

        Integer allCount = projectExamineMapper.searchAllCount();

        // 自旋次数
        int frequency = 0;

        // 自旋操作
        while (allCount!=projectVoList.size()) {
            try {
                projectService.loadProjectsToRedis();
                Thread.sleep(1500);
                frequency++;
                // 再尝试拿一次
                projectVoList = (List<ProjectVo>) opsForValue.get("projectVos");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (frequency>16) {
                break;
            }
        }


        // 遍历projectVoList集合放入一个map中
        HashMap<String ,ProjectVo> tempMap = new HashMap<>();
        for (ProjectVo projectVo : projectVoList) {
            tempMap.put(projectVo.getProjectName(), projectVo);
        }

        // 双重检测机制，防止并发环境下map出错
        synchronized (peFirstMaps) {
            if (!peFirstMaps.isEmpty()) {
                synchronized (peFirstMaps) {
                    peSecondMaps.clear();
                }
            }
        }

        // 双重检测机制，防止并发环境下map出错
        synchronized (peSecondMaps) {
            if (!peSecondMaps.isEmpty()) {
                synchronized (peSecondMaps) {
                    peSecondMaps.clear();
                }
            }
        }

        // 遍历审核表中的内容，把项目文件存入进去
        List<ProjectExamine> projectExamines = projectExamineMapper.searchAllPE();
        for (ProjectExamine projectExamine : projectExamines) {
            ProjectVo projectVo = tempMap.get(projectExamine.getProjectName());
            if (projectVo==null) {
                continue;
            }
            // new一个projectExamineVo，把项目Vo中的文件map放入到projectExamineVo中去
            ProjectExamineVo projectExamineVo = new ProjectExamineVo();
//            projectExamineVo.setFileMap(projectVo.getFileMap());
            BeanUtils.copyProperties(projectExamine,projectExamineVo);
            projectExamineVo.setFileMap(projectVo.getFileMap());
            projectExamineVo.setTeam(projectVo.getTeam());
            // 把Vo放入map中
            peFirstMaps.put(projectExamineVo.getPeId(), projectExamineVo);
            if (projectExamineVo.getStatusId()>1) {
                peSecondMaps.put(projectExamineVo.getPeId(), projectExamineVo);
            }
            /*
            // 判断项目的状态，项目状态为未提交的话，把项目加入到peFirstMaps中
            if (projectExamine.getStatusId().equals(UniversityConstants.PROJECT_STATUS_FIRST_PASS)) {
                // new一个projectExamineVo，把项目Vo中的文件map放入到projectExamineVo中去
                ProjectExamineVo projectExamineVo = new ProjectExamineVo();
//            projectExamineVo.setFileMap(projectVo.getFileMap());
                BeanUtils.copyProperties(projectExamine,projectExamineVo);
                projectExamineVo.setFileMap(projectVo.getFileMap());
                projectExamineVo.setTeam(projectVo.getTeam());
                // 把Vo放入map中
                peFirstMaps.put(projectExamineVo.getPeId(), projectExamineVo);
            }else if (projectExamine.getStatusId().equals(UniversityConstants.PROJECT_STATUS_SECOND_PASS)) {
                // new一个projectExamineVo，把项目Vo中的文件map放入到projectExamineVo中去
                ProjectExamineVo projectExamineVo = new ProjectExamineVo();
//            projectExamineVo.setFileMap(projectVo.getFileMap());
                BeanUtils.copyProperties(projectExamine,projectExamineVo);
                projectExamineVo.setFileMap(projectVo.getFileMap());
                projectExamineVo.setTeam(projectVo.getTeam());
                // 把Vo放入map中
                peSecondMaps.put(projectExamineVo.getPeId(), projectExamineVo);
            }
             */

        }
    }

    @Override
    public RestResult searchPEByDeIdAndSId(Integer pageNum,
                                           Integer pageSize,
                                           Integer departmentId,
                                           Integer statusId,
                                           Integer flag) {
        HashMap<Integer, ProjectExamineVo> map = flag==1?peFirstMaps:peSecondMaps;

        ArrayList<ProjectExamineVo> list = new ArrayList<>();
        for (Map.Entry<Integer, ProjectExamineVo> entry : map.entrySet()) {
            ProjectExamineVo vo = entry.getValue();
            if (vo.getDepartmentId().equals(departmentId) && vo.getStatusId().equals(statusId)) {
                list.add(vo);
            }
        }
        PageInfo pageInfo = PageUtil.startPage(pageNum, pageSize, list);
        return RestResult.success("根据单位和状态搜索初审或者二审的项目如下：")
                .put("data",pageInfo);
    }

    @Override
    public RestResult searchPEByStAndDe(Integer pageNum,
                                        Integer pageSize,
                                        Integer departmentId,
                                        Integer statusId,
                                        Integer flag) {
        // 判断是初审还是二审
        HashMap<Integer, ProjectExamineVo> map = flag==1?peFirstMaps:peSecondMaps;
        ArrayList<ProjectExamineVo> list = new ArrayList<>();

        if (statusId==null && departmentId==null) {
            for (Map.Entry<Integer, ProjectExamineVo> entry : map.entrySet()) {
                ProjectExamineVo vo = entry.getValue();
                list.add(vo);
            }
        } else if (departmentId==null) {
            list = searchPEByStId(statusId,map);
        }else if (statusId==null) {
            list = searchPEByDeId(departmentId, map);
        } else {
            list = searchPEByStAndDe(statusId,departmentId,map);
        }

        PageInfo pageInfo = PageUtil.startPage(pageNum, pageSize, list);;
        return RestResult.success("数据如下")
                .put("data",pageInfo);
    }

    /**
     * 通过部门id搜索
     * @param departmentId 部门id
     * @param map 初审或者二审集合
     * @return ProjectExamineVo的集合
     */
    private ArrayList searchPEByDeId(Integer departmentId,HashMap<Integer, ProjectExamineVo> map) {
        ArrayList<ProjectExamineVo> vos = new ArrayList<>();
        for (Map.Entry<Integer, ProjectExamineVo> entry : map.entrySet()) {
            ProjectExamineVo value = entry.getValue();
            if (value.getDepartmentId().equals(departmentId)) {
                vos.add(value);
            }
        }
        return vos;
    }

    /**
     * 通过状态id搜索
     * @param statusId 状态id
     * @param map 初审或者二审集合
     * @return ProjectExamineVo的集合
     */
    private ArrayList searchPEByStId(Integer statusId,HashMap<Integer, ProjectExamineVo> map) {
        ArrayList<ProjectExamineVo> vos = new ArrayList<>();
        for (Map.Entry<Integer, ProjectExamineVo> entry : map.entrySet()) {
            ProjectExamineVo value = entry.getValue();
            if (value.getStatusId().equals(statusId)) {
                vos.add(value);
            }
        }
        return vos;
    }

    /**
     * 通过状态id和部门id
     * @param statusId 状态id
     * @param departmentId 部门id
     * @param map 初审或者二审集合
     * @return ProjectExamineVo的集合
     */
    private ArrayList searchPEByStAndDe(Integer statusId,Integer departmentId, HashMap<Integer, ProjectExamineVo> map) {
        ArrayList<ProjectExamineVo> vos = new ArrayList<>();
        for (Map.Entry<Integer, ProjectExamineVo> entry : map.entrySet()) {
            ProjectExamineVo value = entry.getValue();
            if (value.getStatusId().equals(statusId) && value.getDepartmentId().equals(departmentId)) {
                vos.add(value);
            }
        }
        return vos;
    }

}
